package edu.pku.sei.ocl.value;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.ecore.EClassifier;

import edu.pku.sei.ocl.types.TypesPackage;
import edu.pku.sei.ocl.utilities.OCLStandardLibrary;

public class OCLBasicCollection extends BasicEList<Object> implements OCLCollection {
	private static final long serialVersionUID = -4593025557627918468L;
	private final EClassifier elementOclType;
	private final CollectionTypeEnum collectionType;
	
	public OCLBasicCollection(EClassifier etype,CollectionTypeEnum ctype){
		this(etype,ctype,5);
	}
	
	public OCLBasicCollection(EClassifier etype,CollectionTypeEnum ctype,int size){
		super(size);
		elementOclType = etype;
		collectionType = ctype;
	}
	
	

	public OCLBasicCollection() {
		this(TypesPackage.eINSTANCE.getOclAny(),CollectionTypeEnum.Collection);
	}

	@Override
	protected boolean isUnique() {
		switch(getCollectionType()){
		case Set:
			return true;
		case Bag:
			return false;
		case Sequence:
			return false;
		case OrderedSet:
			return true;
		case Collection:
			return false;
		}
		return super.isUnique();
	}
	
	protected boolean isOrdered(){
		switch(getCollectionType()){
		case Set:
			return false;
		case Bag:
			return false;
		case Sequence:
			return true;
		case OrderedSet:
			return true;
		case Collection:
			return false;
		}
		return false;
	}
	
	public boolean equals(Object r){
		if(r==this)
			return true;
		
		if(r instanceof OCLBasicCollection){
			OCLBasicCollection oc = (OCLBasicCollection)r;
			if(oc.getElementOclType()!=this.getElementOclType())
				return false;
			if(oc.getCollectionType()!=this.getCollectionType())
				return false;
			if(oc.size()!=this.size())
				return false;
			
			if(isOrdered()){
				for(int i=0;i<oc.size();i++){
					if(!oc.get(i).equals(this.get(i)))
						return false;
				}
				return true;
			} else {
				int mapToOC[] = new int[oc.size()];
				for(int i=0;i<mapToOC.length;i++){
					mapToOC[i]=-1;
				}
				
				boolean flag = false;
				
				for(int i=0;i<oc.size();i++){
					Object elem = oc.get(i);
					for(int j=0;j<size();j++){
						if(mapToOC[j]==-1&&get(j).equals(elem)){
							mapToOC[j]=i;
							flag = true;
							break;
						}
					}
					if(flag==false)
						return false;
				}
				return true;
			}
		} else if(this.getElementOclType()==OCLStandardLibrary.oclType(r)){
			if(this.size==1&&this.get(0).equals(r))
				return true;
			else return false;
		}
		
		return super.equals(r);
	}

//	@Override
//	public void addUnique(Object object) {
//		if(isOrdered()&&isUnique()==false){
//			Object e = validate(size, object);
//			int index = this.indexOf(e);
//			if(index==-1)
//				index = size;
//			else {
//				while((data[index]==e || data[index].equals(e))&&index<size)
//					index++;
//			}
//			super.addUnique(index, e);
//		} else
//			super.addUnique(object);
//	}
//
//	@Override
//	public boolean addAll(Collection<? extends Object> collection) {
//		if(isOrdered()&&isUnique()==false){
//			for(Object e : collection){
//				add(e);
//			}
//		}
//		return super.addAll(collection);
//	}

	@Override
	public void removeAll(Object e){
		while(remove(e));
	}

	/* (non-Javadoc)
	 * @see edu.pku.sei.ocl.value.IOclCollection#getElementOclType()
	 */
	@Override
	public EClassifier getElementOclType() {
		return elementOclType;
	}

	/* (non-Javadoc)
	 * @see edu.pku.sei.ocl.value.IOclCollection#getCollectionType()
	 */
	@Override
	public CollectionTypeEnum getCollectionType() {
		return collectionType;
	}

	@Override
	public boolean isConstant() {
		return isConstant;
	}

	private boolean isConstant = false;
	@Override
	public void collectionLiteral(boolean flag) {
		isConstant = flag;
	}
	
}
